package com.qf.application.interceprot;

import com.auth0.jwt.JWT;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.qf.application.commons.exception.BusinessException;
import com.qf.application.commons.exception.UserTokenExpiredException;
import com.qf.application.commons.exception.UserTokenIsNullException;
import com.qf.application.commons.utils.JWTUtils;
import com.qf.application.commons.utils.R;
import com.qf.application.context.UserContextHolder;
import com.qf.application.entity.LoginUser;
import com.qf.application.entity.UserToken;
import com.qf.application.service.impl.UserTokenService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

/**
 * 对Token进行校验
 * 如果教程成功就放行，失败就提示用户token有误
 */
@Component
@Slf4j
public class UserTokenInterceptor implements HandlerInterceptor {

    @Autowired
    private UserTokenService tokenService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.debug("完成的登录校验");

        // 1.从请起头中获取token
        String token = request.getHeader("token");

        // 2.token非空校验
        if (ObjectUtils.isEmpty(token)) {

            // 如果请求头中没有token，尝试客户端是不是把token传递到了地址栏(查询参数)
            token = request.getParameter("token");
            if (ObjectUtils.isEmpty(token)) {
                throw new UserTokenIsNullException(1001, "token不能为空");
            }
        }

        // 3.校验Token的合法性(过期，有误)，如果校验失败会抛出异常
        Map<String, Object> map = null;
        try {
            map = JWTUtils.getUserToken(token);
        } catch (TokenExpiredException e) {  // 如果抛出该异常说明token过期，需要提示用户重新登录
            throw new BusinessException(1003, "token有误，请重新登录");
        } catch (JWTVerificationException e) { // 如果抛出异常，说明token认证失败
            throw new BusinessException(1003, "token有误，请重新登录");
        }

        // 4.从Map中找出UUID
        String uuid = (String) map.get("uuid");

        // 5.根据UUID去redis中按查询登录信息
        LoginUser loginUser = tokenService.getLoginUser(uuid);
        if (loginUser == null) {
            throw new BusinessException(1003, "您还没有登录，请先登录");
        }

        UserContextHolder.set(loginUser);
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // Controller调用完之后删除当前线程中的用户登录信息
        UserContextHolder.remove();
    }
}
